import { type ChangeEvent, type MouseEvent, useContext, useState } from 'react';
import type {
  IClientFile,
  IUploadMessageSendFile,
  IUploadMessageSendFileBody,
  IUploadPostContent,
  IUploadPostContentBody,
  IUploadPostNewFile,
  IUploadPostNewFileBody,
  IUploadPostTemplateFile,
  IUploadPostTemplateFileBody,
  IUploadSectionContentBody,
  IUploadSectionContentFile,
} from '@/interfaces';
import type { TBody } from '@/types';
import { useMutation, useQuery } from '@tanstack/react-query';
import {
  queryUserFiles,
  removeFile,
  uploadMessageSendFile,
  uploadPostContent,
  uploadPostNewFile,
  uploadPostTemplateFile,
  uploadSectionContent,
} from '@/services/api';
import FileItem from '@/app/[locale]/file/file-item';
import { AppContext } from '@/contexts/app';
import classNames from 'classnames';
import AlertLoad from '@/app/[locale]/alert/load';
import Alert from '@/app/[locale]/alert/alert';
import useToast from '@/hooks/useToast';
import Nodata from '@/app/[locale]/common/nodata/nodata';

export type TFileManagerTranslatedField =
  | 'startUpload'
  | 'selectFilePlaceholder'
  | 'select'
  | 'delete'
  | 'deleteCompleted'
  | 'selectFileToDelete'
  | 'uploadCompleted'
  | 'fileDoesNotExist';

export default function FileManager(
  this: any,
  {
    id,
    type,
    options,
    onCloseModal,
    translatedFields = {
      startUpload: '开始上传',
      selectFilePlaceholder: '请选择文件',
      select: '选择',
      delete: '删除',
      deleteCompleted: '删除完成',
      selectFileToDelete: '请选择要删除的文件',
      uploadCompleted: '上传完成',
      fileDoesNotExist: '文件不存在',
    },
  }: {
    id?: number;
    type: 'message' | 'post' | 'postTemplate' | 'section';
    options: {
      onClose: Function;
      onSelect: Function;
    };
    onCloseModal: () => void;
    translatedFields?: Record<TFileManagerTranslatedField, any>;
  },
) {
  const { show } = useToast();
  const context = useContext(AppContext);
  const metadata = context.metadata!;
  const appOssServer = metadata.env.APP_OSS_SERVER;
  const [tabIndex, setTabIndex] = useState(1);
  const [itemIndex, setItemIndex] = useState(-1);
  const [form, setForm] = useState({
    uploadFile: '',
    file: '',
    fileUrl: '',
  });

  const clientQueryUserFilesQuery = useQuery(
    ['/file', '/user'],
    async () => {
      return (await queryUserFiles()) as IClientFile[];
    },
    {
      enabled: tabIndex === 2,
    },
  );

  const uploadSectionContentMutation = useMutation(
    async (variables: TBody<IUploadSectionContentBody>) => {
      return (await uploadSectionContent(
        variables,
      )) as IUploadSectionContentFile;
    },
  );
  const uploadPostContentMutation = useMutation(
    async (variables: TBody<IUploadPostContentBody>) => {
      return (await uploadPostContent(variables)) as IUploadPostContent;
    },
  );
  const uploadPostNewContentMutation = useMutation(
    async (variables: TBody<IUploadPostNewFileBody>) => {
      return (await uploadPostNewFile(variables)) as IUploadPostNewFile;
    },
  );
  const uploadPostTemplateFileMutation = useMutation(
    async (variables: TBody<IUploadPostTemplateFileBody>) => {
      return (await uploadPostTemplateFile(
        variables,
      )) as IUploadPostTemplateFile;
    },
  );
  const uploadMessageSendFileMutation = useMutation(
    async (variables: TBody<IUploadMessageSendFileBody>) => {
      return (await uploadMessageSendFile(variables)) as IUploadMessageSendFile;
    },
  );
  const clientRemoveFileMutation = useMutation(
    async (variables: TBody<void>) => {
      await removeFile(variables);
    },
  );

  function onClickItem(item: IClientFile) {
    setItemIndex(item.id);
  }

  async function onClickDeleteFile() {
    try {
      if (itemIndex === -1) {
        show({
          type: 'DANGER',
          message: translatedFields.selectFileToDelete,
        });
        return;
      }

      await clientRemoveFileMutation.mutateAsync({
        id: itemIndex,
      });

      setItemIndex(-1);
      await clientQueryUserFilesQuery.refetch({ throwOnError: true });

      show({
        type: 'SUCCESS',
        message: translatedFields.deleteCompleted,
      });
    } catch (e) {
      clientRemoveFileMutation.reset();
      show({
        type: 'DANGER',
        message: e,
      });
    }
  }

  function onClickSelectFile() {
    const files = clientQueryUserFilesQuery.data as IClientFile[];
    if (!files.length) {
      show({
        type: 'INFO',
        message: translatedFields.fileDoesNotExist,
      });
      return;
    } else if (itemIndex === -1) {
      show({
        type: 'INFO',
        message: translatedFields.selectFilePlaceholder,
      });
      return;
    }

    const data = clientQueryUserFilesQuery.data as IClientFile[];
    const find = data.find((item) => item.id === itemIndex);
    if (!find) {
      show({
        type: 'DANGER',
        message: translatedFields.fileDoesNotExist,
      });
      return;
    }

    options.onSelect({
      ...find,
      urls: { ...find.urls, default: appOssServer + find.urls.default },
    });
    onCloseModal();
  }

  async function onClickUploadFile() {
    try {
      const { file } = form;
      if (!file) {
        show({
          type: 'DANGER',
          message: translatedFields.fileDoesNotExist,
        });
        return;
      }

      const body = {
        file,
      };

      let result;
      if (type === 'post') {
        if (id) {
          result = await uploadPostContentMutation.mutateAsync({
            id,
            data: body,
          });
        } else {
          result = await uploadPostNewContentMutation.mutateAsync({
            data: body,
          });
        }
      } else if (type === 'section') {
        result = await uploadSectionContentMutation.mutateAsync({
          id,
          data: body,
        });
      } else if (type === 'message') {
        result = await uploadMessageSendFileMutation.mutateAsync({
          id,
          data: body,
        });
      } else if (type === 'postTemplate') {
        result = await uploadPostTemplateFileMutation.mutateAsync({
          id,
          data: body,
        });
      } else {
        return;
      }

      await clientQueryUserFilesQuery.refetch({ throwOnError: true });

      setForm({
        ...form,
        uploadFile: '',
        file: '',
        fileUrl: result.urls.default,
      });

      show({
        type: 'SUCCESS',
        message: translatedFields.uploadCompleted,
      });
    } catch (e) {
      if (type === 'section') {
        uploadSectionContentMutation.reset();
      } else if (type === 'message') {
        uploadMessageSendFileMutation.reset();
      } else if (type === 'postTemplate') {
        uploadPostTemplateFileMutation.reset();
      } else if (type === 'post') {
        if (id) {
          uploadPostContentMutation.reset();
        } else {
          uploadPostNewContentMutation.reset();
        }
      }

      show({
        type: 'DANGER',
        message: e,
      });
    }
  }

  function onChangeForm(e: ChangeEvent<HTMLInputElement>) {
    const name = e.target.name;
    const value = e.target.value;

    if (name === 'uploadFile') {
      const file = (e.target as any).files[0];
      setForm({
        ...form,
        [name]: value,
        file,
      });
    } else {
      setForm({
        ...form,
        [name]: value,
      });
    }
  }

  function onClickNavItem(index: number, e: MouseEvent<HTMLAnchorElement>) {
    e.stopPropagation();
    e.preventDefault();
    setTabIndex(index);
  }

  return (
    <div className="vstack gap-4">
      <ul className="nav nav-pills justify-content-center my-4">
        <li className="nav-item">
          <a
            className={classNames('nav-link', {
              active: tabIndex === 1,
            })}
            onClick={onClickNavItem.bind(this, 1)}
            href="#"
          >
            上传文件
          </a>
        </li>
        <li className="nav-item">
          <a
            className={classNames('nav-link', {
              active: tabIndex === 2,
            })}
            href="#"
            onClick={onClickNavItem.bind(this, 2)}
          >
            浏览文件
          </a>
        </li>
      </ul>

      {tabIndex === 1 && (
        <div className="input-group my-4">
          <input
            type="file"
            accept=".zip,.rar,.7z,image/*"
            className="form-control"
            name="uploadFile"
            value={form.uploadFile}
            onChange={onChangeForm}
            aria-label="Upload"
          />
          <button
            disabled={
              uploadPostContentMutation.isLoading ||
              uploadSectionContentMutation.isLoading ||
              uploadPostNewContentMutation.isLoading
            }
            onClick={onClickUploadFile}
            className="btn btn-outline-secondary"
            type="button"
          >
            {(uploadPostContentMutation.isLoading ||
              uploadSectionContentMutation.isLoading ||
              uploadPostNewContentMutation.isLoading) && (
              <div
                className="spinner-border text-secondary me-2 spinner-border-sm"
                role="status"
              >
                <span className="visually-hidden">Loading...</span>
              </div>
            )}
            {translatedFields.startUpload}
          </button>
        </div>
      )}

      {tabIndex === 2 && (
        <>
          {clientQueryUserFilesQuery.data &&
          clientQueryUserFilesQuery.data.length > 0 ? (
            <>
              <div>
                <button
                  disabled={clientRemoveFileMutation.isLoading}
                  onClick={onClickDeleteFile}
                  type="button"
                  className="btn btn-outline-primary"
                >
                  {clientRemoveFileMutation.isLoading ? (
                    <span
                      className="spinner-border spinner-border-sm me-2"
                      aria-hidden="true"
                    ></span>
                  ) : (
                    <i className="bi bi-trash me-2"></i>
                  )}
                  {translatedFields.delete}
                </button>
              </div>
              <div className="row row-cols-auto">
                {clientQueryUserFilesQuery.data.map((item) => {
                  return (
                    <div key={item.id} className="col mb-3">
                      <FileItem
                        item={item}
                        onClickItem={onClickItem.bind(this, item)}
                        itemIndex={itemIndex}
                        oss={appOssServer}
                      />
                    </div>
                  );
                })}
              </div>
              <div className="text-end my-4">
                <button
                  onClick={onClickSelectFile}
                  type="button"
                  className="btn btn-success"
                >
                  {translatedFields.select}
                </button>
              </div>
            </>
          ) : (
            <Nodata />
          )}

          {clientQueryUserFilesQuery.isError && (
            <Alert message={clientQueryUserFilesQuery.error} type="error" />
          )}

          {clientQueryUserFilesQuery.isLoading && <AlertLoad />}
        </>
      )}
    </div>
  );
}
